package com.example.backend.service;

import com.example.backend.domain.entity.Ticket;
import com.example.backend.domain.entity.TicketSLA;
import com.example.backend.domain.enums.TicketStatus;
import com.example.backend.repository.TicketSLARepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * SLA时间跟踪服务
 * 记录和跟踪工单的响应时间和解决时间
 */
@Service
@Transactional
public class TicketSLATrackingService {

    @Autowired
    private TicketSLARepository slaRepository;

    @Autowired
    private TicketPriorityManagementService priorityService;

    /**
     * SLA状态枚举
     */
    public enum SLAStatus {
        ON_TIME("按时"),
        WARNING("警告"),
        VIOLATED("违反"),
        NOT_APPLICABLE("不适用");

        private final String description;

        SLAStatus(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    /**
     * SLA跟踪结果
     */
    public static class SLATrackingResult {
        private SLAStatus responseStatus;
        private SLAStatus resolutionStatus;
        private Instant responseDeadline;
        private Instant resolutionDeadline;
        private Duration responseTimeRemaining;
        private Duration resolutionTimeRemaining;
        private boolean responseViolated;
        private boolean resolutionViolated;
        private String responseStatusDescription;
        private String resolutionStatusDescription;

        // Getters and Setters
        public SLAStatus getResponseStatus() { return responseStatus; }
        public void setResponseStatus(SLAStatus responseStatus) { this.responseStatus = responseStatus; }
        public SLAStatus getResolutionStatus() { return resolutionStatus; }
        public void setResolutionStatus(SLAStatus resolutionStatus) { this.resolutionStatus = resolutionStatus; }
        public Instant getResponseDeadline() { return responseDeadline; }
        public void setResponseDeadline(Instant responseDeadline) { this.responseDeadline = responseDeadline; }
        public Instant getResolutionDeadline() { return resolutionDeadline; }
        public void setResolutionDeadline(Instant resolutionDeadline) { this.resolutionDeadline = resolutionDeadline; }
        public Duration getResponseTimeRemaining() { return responseTimeRemaining; }
        public void setResponseTimeRemaining(Duration responseTimeRemaining) { this.responseTimeRemaining = responseTimeRemaining; }
        public Duration getResolutionTimeRemaining() { return resolutionTimeRemaining; }
        public void setResolutionTimeRemaining(Duration resolutionTimeRemaining) { this.resolutionTimeRemaining = resolutionTimeRemaining; }
        public boolean isResponseViolated() { return responseViolated; }
        public void setResponseViolated(boolean responseViolated) { this.responseViolated = responseViolated; }
        public boolean isResolutionViolated() { return resolutionViolated; }
        public void setResolutionViolated(boolean resolutionViolated) { this.resolutionViolated = resolutionViolated; }
        public String getResponseStatusDescription() { return responseStatusDescription; }
        public void setResponseStatusDescription(String responseStatusDescription) { this.responseStatusDescription = responseStatusDescription; }
        public String getResolutionStatusDescription() { return resolutionStatusDescription; }
        public void setResolutionStatusDescription(String resolutionStatusDescription) { this.resolutionStatusDescription = resolutionStatusDescription; }
    }

    /**
     * 创建或更新工单SLA记录
     * 
     * @param ticket 工单
     * @return SLA记录
     */
    public TicketSLA createOrUpdateSLA(Ticket ticket) {
        Optional<TicketSLA> existingSLA = slaRepository.findByTicketId(ticket.getId());
        
        TicketSLA sla;
        if (existingSLA.isPresent()) {
            sla = existingSLA.get();
        } else {
            sla = new TicketSLA();
            sla.setTicketId(ticket.getId());
        }

        // 设置SLA时间
        sla.setResponseDeadline(priorityService.calculateResponseSLA(ticket.getPriority(), ticket.getCreatedAt()));
        sla.setResolutionDeadline(priorityService.calculateResolutionSLA(ticket.getPriority(), ticket.getCreatedAt()));
        
        // 设置首次响应时间（如果还没有设置）
        if (sla.getFirstResponseAt() == null && ticket.getStatus() != TicketStatus.OPEN) {
            sla.setFirstResponseAt(Instant.now());
        }

        // 设置解决时间（如果工单已解决）
        if (ticket.getStatus() == TicketStatus.RESOLVED && sla.getResolvedAt() == null) {
            sla.setResolvedAt(ticket.getResolvedAt() != null ? ticket.getResolvedAt() : Instant.now());
        }

        sla.setUpdatedAt(Instant.now());
        return slaRepository.save(sla);
    }

    /**
     * 记录首次响应时间
     * 
     * @param ticketId 工单ID
     * @param responseTime 响应时间
     */
    public void recordFirstResponse(Long ticketId, Instant responseTime) {
        Optional<TicketSLA> slaOpt = slaRepository.findByTicketId(ticketId);
        if (slaOpt.isPresent()) {
            TicketSLA sla = slaOpt.get();
            if (sla.getFirstResponseAt() == null) {
                sla.setFirstResponseAt(responseTime);
                sla.setUpdatedAt(Instant.now());
                slaRepository.save(sla);
            }
        }
    }

    /**
     * 记录解决时间
     * 
     * @param ticketId 工单ID
     * @param resolvedTime 解决时间
     */
    public void recordResolution(Long ticketId, Instant resolvedTime) {
        Optional<TicketSLA> slaOpt = slaRepository.findByTicketId(ticketId);
        if (slaOpt.isPresent()) {
            TicketSLA sla = slaOpt.get();
            sla.setResolvedAt(resolvedTime);
            sla.setUpdatedAt(Instant.now());
            slaRepository.save(sla);
        }
    }

    /**
     * 获取工单的SLA跟踪结果
     * 
     * @param ticket 工单
     * @return SLA跟踪结果
     */
    public SLATrackingResult getSLATrackingResult(Ticket ticket) {
        SLATrackingResult result = new SLATrackingResult();
        
        // 计算SLA截止时间
        Instant responseDeadline = priorityService.calculateResponseSLA(ticket.getPriority(), ticket.getCreatedAt());
        Instant resolutionDeadline = priorityService.calculateResolutionSLA(ticket.getPriority(), ticket.getCreatedAt());
        
        result.setResponseDeadline(responseDeadline);
        result.setResolutionDeadline(resolutionDeadline);

        // 获取SLA记录
        Optional<TicketSLA> slaOpt = slaRepository.findByTicketId(ticket.getId());
        
        Instant now = Instant.now();
        
        // 计算响应时间SLA状态
        if (slaOpt.isPresent() && slaOpt.get().getFirstResponseAt() != null) {
            // 已有首次响应
            Instant firstResponse = slaOpt.get().getFirstResponseAt();
            if (firstResponse.isBefore(responseDeadline)) {
                result.setResponseStatus(SLAStatus.ON_TIME);
                result.setResponseStatusDescription("按时响应");
            } else {
                result.setResponseStatus(SLAStatus.VIOLATED);
                result.setResponseStatusDescription("响应超时");
                result.setResponseViolated(true);
            }
        } else {
            // 尚未响应
            Duration remaining = Duration.between(now, responseDeadline);
            result.setResponseTimeRemaining(remaining);
            
            if (remaining.isNegative()) {
                result.setResponseStatus(SLAStatus.VIOLATED);
                result.setResponseStatusDescription("响应超时");
                result.setResponseViolated(true);
            } else if (remaining.toMinutes() <= 60) {
                result.setResponseStatus(SLAStatus.WARNING);
                result.setResponseStatusDescription("即将超时");
            } else {
                result.setResponseStatus(SLAStatus.ON_TIME);
                result.setResponseStatusDescription("正常");
            }
        }

        // 计算解决时间SLA状态
        if (ticket.getStatus() == TicketStatus.RESOLVED || ticket.getStatus() == TicketStatus.CLOSED) {
            // 工单已解决
            Instant resolvedTime = ticket.getResolvedAt() != null ? ticket.getResolvedAt() : now;
            if (resolvedTime.isBefore(resolutionDeadline)) {
                result.setResolutionStatus(SLAStatus.ON_TIME);
                result.setResolutionStatusDescription("按时解决");
            } else {
                result.setResolutionStatus(SLAStatus.VIOLATED);
                result.setResolutionStatusDescription("解决超时");
                result.setResolutionViolated(true);
            }
        } else {
            // 工单尚未解决
            Duration remaining = Duration.between(now, resolutionDeadline);
            result.setResolutionTimeRemaining(remaining);
            
            if (remaining.isNegative()) {
                result.setResolutionStatus(SLAStatus.VIOLATED);
                result.setResolutionStatusDescription("解决超时");
                result.setResolutionViolated(true);
            } else if (remaining.toHours() <= 4) {
                result.setResolutionStatus(SLAStatus.WARNING);
                result.setResolutionStatusDescription("即将超时");
            } else {
                result.setResolutionStatus(SLAStatus.ON_TIME);
                result.setResolutionStatusDescription("正常");
            }
        }

        return result;
    }

    /**
     * 获取违反SLA的工单列表
     * 
     * @return 违反SLA的工单ID列表
     */
    public List<Long> getViolatedSLATickets() {
        return slaRepository.findViolatedSLATickets(Instant.now());
    }

    /**
     * 获取即将违反SLA的工单列表
     * 
     * @param warningHours 警告小时数
     * @return 即将违反SLA的工单ID列表
     */
    public List<Long> getWarningSLATickets(int warningHours) {
        Instant warningTime = Instant.now().plus(Duration.ofHours(warningHours));
        return slaRepository.findWarningSLATickets(warningTime, Instant.now());
    }

    /**
     * 计算SLA达成率
     * 
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return SLA达成率统计
     */
    public Map<String, Object> calculateSLAAchievementRate(Instant startDate, Instant endDate) {
        List<TicketSLA> slaRecords = slaRepository.findByCreatedAtBetween(startDate, endDate);
        
        int totalTickets = slaRecords.size();
        int responseOnTime = 0;
        int resolutionOnTime = 0;
        
        for (TicketSLA sla : slaRecords) {
            if (sla.getFirstResponseAt() != null && 
                sla.getFirstResponseAt().isBefore(sla.getResponseDeadline())) {
                responseOnTime++;
            }
            
            if (sla.getResolvedAt() != null && 
                sla.getResolvedAt().isBefore(sla.getResolutionDeadline())) {
                resolutionOnTime++;
            }
        }
        
        double responseRate = totalTickets > 0 ? (double) responseOnTime / totalTickets * 100 : 0;
        double resolutionRate = totalTickets > 0 ? (double) resolutionOnTime / totalTickets * 100 : 0;
        
        return Map.of(
            "totalTickets", totalTickets,
            "responseOnTime", responseOnTime,
            "resolutionOnTime", resolutionOnTime,
            "responseAchievementRate", Math.round(responseRate * 100.0) / 100.0,
            "resolutionAchievementRate", Math.round(resolutionRate * 100.0) / 100.0
        );
    }

    /**
     * 获取SLA统计报告
     * 
     * @return SLA统计报告
     */
    public Map<String, Object> getSLAStatistics() {
        long totalSLARecords = slaRepository.count();
        long violatedResponse = slaRepository.countViolatedResponseSLA(Instant.now());
        long violatedResolution = slaRepository.countViolatedResolutionSLA(Instant.now());
        
        return Map.of(
            "totalSLARecords", totalSLARecords,
            "violatedResponseSLA", violatedResponse,
            "violatedResolutionSLA", violatedResolution,
            "responseViolationRate", totalSLARecords > 0 ? 
                Math.round((double) violatedResponse / totalSLARecords * 10000) / 100.0 : 0,
            "resolutionViolationRate", totalSLARecords > 0 ? 
                Math.round((double) violatedResolution / totalSLARecords * 10000) / 100.0 : 0
        );
    }

    /**
     * 清理过期的SLA记录
     * 
     * @param daysToKeep 保留天数
     * @return 清理的记录数
     */
    public int cleanupExpiredSLARecords(int daysToKeep) {
        Instant cutoffDate = Instant.now().minus(Duration.ofDays(daysToKeep));
        List<TicketSLA> expiredRecords = slaRepository.findByCreatedAtBefore(cutoffDate);
        
        int count = expiredRecords.size();
        slaRepository.deleteAll(expiredRecords);
        
        return count;
    }
}
